<?php
/**
 * Establish a database connection on behalf of the user.
 * If parameters are NULL, the information shall be loaded from the config.php
 * in the root directory of the site.
 * 
 * @param array $conn_info
 *   An array of connection information. Contents are as follows:
 *   'user' => The user to access the database as; defaults to the name, if set.
 *   'pass' => The password to access the database as, no default checked.
 *   'name' => The database to connect to; defaults to the user if set.
 *   'host' => The host of the database; defaults to 'localhost' if not set.
 *   'port' => The port to access the database through, defaults to 3306 if not set
 * 
 *   If all of user pass and name are are not set, the file connect.php will be
 *     included, so there can be overrides there.
 * @return $conn
 *   A mysqli database connection, ready for use if successful, FALSE otherwise.
 */
function database_connection(array $conn_info = array()) {
  $defaults = array(
    'user' => NULL,
    'pass' => NULL,
    'name' => NULL,
    'host' => 'localhost',
    'port' => '3306',
  );
  $conn_info = array_merge($conn_info, $defaults);
  if (!database_validate($conn_info)) {
    $prefix = constant('prefix');
    $file = $prefix . '/connect.php';
    if (file_exists($file)) {
      include_once($file); 
      if (!database_validate($conn_info)) {
        return FALSE;
      }
    }
  }
  if (!$conn_info['user']) {
    $conn_info['user'] = $conn_info['name'];
  }
  else if (!$conn_info['name']) {
    $conn_info['name'] = $conn_info['user'];
  }
  global $conn;
  $conn = new mysqli($conn_info['host'], $conn_info['user'], $conn_info['pass'], $conn_info['name']);
  if ($conn->connect_errno) {
    return FALSE;
  }
  return $conn;
}

/**
 * See if the required information has been passed.
 * 
 * @param array $conn_info
 *   The array of access information; see database_connection for structure.
 * @return boolean
 *   FALSE if not enough information is here to connect, TRUE otherwise.
 */
function database_validate(array $conn_info) {
  if (!$conn_info['pass']) {
    return FALSE;
  }
  if (!$conn_info['user'] && !$conn_info['name']) {
    return FALSE;
  }
  return TRUE;
}

/**
 * Query the database.
 * 
 * @param $query
 *   The query for the database.
 *   Set this to FALSE for single lines of the previous query.
 * @param array $vars = array()
 *   The variables to substitute into the $query for question marks prior to execution.
 * @param $type = MYSQL_ASSOC
 *   Types of return data. One of MYSQLI_ASSOC, MYSQLI_NUM, or MYSQLI_BOTH.
 *   @link http://www.php.net/manual/en/mysqli-result.fetch-all.php 
 * @param boolean $part = FALSE
 *   If TRUE, this will return the next line of the passed query, leaving it
 *   prepared for future calls.
 * @return $result
 */
function database_query($query, array $vars = array(), string $type = MYSQLI_ASSOC, $part = FALSE) {
  global $conn;
  if (!isset($conn)) {
    database_connection();
  }
  if($query) {
    $statement = $conn->prepare($query);
  }
  if (!empty($vars)) {
    foreach($vars as $item) {
      $var_type = database_type($item);
      $statement::bind_param($var_type, $item);
    }
  }
  $statement->execute();
  if (!$query || $part) {
    $return = $statement::fetch($type);
    if (is_null($return)) {
      $statement->close();
    }
    return $return;
  }
  $return = $statement->fetchAll($type);
  $statement->close();
  return $return;
}

/**
 * Small function to quickly determine the type of variable for binding purposes.
 * 
 * @param $value
 *  The value to determine.
 * @return char
 *  One of 'i', 'd', 's' or 'b', in that order of precedence.
 */
function database_type($value) {
  if (is_numeric($value)) {
    if (is_int($value+0)) {
      return 'i';
    }
    return 'd';
  }
  if (is_string($value)) {
    return 's';
  }
  return 'b';
}

function database_query($query, array $args = array(), $part = FALSE) {
  global $conn;
  global $result;
  if (!isset($conn)) {
    database_connection();
  }
  if ($query) {
    $statement = $conn->prepare($query);
  }
  $type = '';
  foreach($args as $key=>$item) {
    if (is_numeric($item)) {
      $args[$key] = $item+0;
      if (is_int($item+0)) {
        $type .= 'i';
      }
      else {
        $type .= 'd';
      }
    }
    else if (is_string($item)) {
      $type .= 's';
    }
    else {
      $type .= 'b';
    }
  }
  $statement::bind_param();
  
}

/**
 * Dates are hairy things. This function converts from from one format
 * to another.
 * 
 * @param $date
 *   The date to manipulate. Could be an english formatted string or a unix epoch
 * @param $format = NULL
 *   The date format to return. If NULL, this will presume its returning it to the database.
 */
function database_date($date, $format = NULL) {
  
  if (is_null($format)) {
    if (is_numeric($date) && is_int($date+0)) {
      return date('Y-m-d H:i:s',$date);
    }
    return strtotime($date);
  }
  // If a format was passed, and epoch style,
  if (is_numeric($date) && is_int($date+0)) {
    return date($format,$date);
  }
  return date($format,strtotime($date));
}

/**
 * Prepare and Perform any binding needed prior to execution. More for inserts or updates.
 * 
 * @param $query
 *  The prepared database statement.
 * @param $variables
 *  The values to bind to the query, can be a primitive type or an array of types.
 * @return $statement
 *  An executed statement, ready to be fetched from.
 */
function database_execute($query,$variables = NULL) {
  global $conn;
  if (empty($conn)) {
  	database_connection();
  }
  $statement = $conn->prepare($query);
  if ($variables && !is_array($variables)) {
  	$type = database_type($variables);
  	$statement->bind_param($type, $variables);
  }
  else {
    foreach($variables as $item) {
  	  $type = database_type($item);
	  $statement->bind_param($type,$item);
	}
  }
  $statement->execute();
  return $statement;
}
